package net.dubboclub.dubbom.launcher;

import com.alibaba.dubbo.common.utils.ConfigUtils;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.compressors.CompressorException;
import org.apache.commons.compress.compressors.CompressorInputStream;
import org.apache.commons.compress.compressors.CompressorStreamFactory;
import org.apache.commons.compress.utils.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.io.*;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @date: 2016/3/11.
 * @author:bieber.
 * @project:DubboM.
 * @package:net.dubboclub.dubbom.launcher.
 * @version:1.0.0
 * @fix:
 * @description: DubboM启动器
 */
public class Launcher {

    private static volatile boolean running=true;

    private static volatile ClassPathXmlApplicationContext applicationContext;

    private static final String COMPRESS_FILE_EXT=".tar.gz";

    private static final String CONSOLE_FORMAT="| %-84s |\n";

    public static void main(String[] args){
        StringBuffer info = new StringBuffer();
        printHead(info);
        printConfig(info);
        if(args.length<=0){
            throw new IllegalArgumentException("args must not be null.");
        }
        String command = args[0];
        if("start".equalsIgnoreCase(command)){
            start(info);

        }else if("stop".equalsIgnoreCase(command)){
            stop();
        }else{
            throw new IllegalArgumentException("Unknow "+command+" argument.");
        }
    }

    private static void clean(File root){
        if(root.isDirectory()){
            File[] children = root.listFiles();
            for(File child:children){
                clean(child);
            }
            root.delete();
        }else{
            root.delete();
        }
    }

    private static void printHead(StringBuffer stringBuffer){
        pringLIne(stringBuffer);
        stringBuffer.append(String.format("|                                   DubboM(Dubbo micro services)                       |\n"));
        stringBuffer.append(String.format("|                                          Version 1.0                                 |\n"));
        stringBuffer.append(String.format("|                                     Powered by DubboClub                             |\n"));

    }

    private static void printConfig(StringBuffer stringBuffer){
        pringLIne(stringBuffer);
        stringBuffer.append(String.format(CONSOLE_FORMAT,new Date()));
        stringBuffer.append(String.format(CONSOLE_FORMAT,"work dir:"+System.getProperty("work.dir")));
        stringBuffer.append(String.format(CONSOLE_FORMAT,"application name:"+ConfigUtils.getProperty("dubbo.application.name")));
        stringBuffer.append(String.format(CONSOLE_FORMAT,"application owner:"+ConfigUtils.getProperty("dubbo.application.owner")));
        stringBuffer.append(String.format(CONSOLE_FORMAT,"protocol:"+ConfigUtils.getProperty("dubbo.protocol.name","default")));
        stringBuffer.append(String.format(CONSOLE_FORMAT,"contextpath:"+ConfigUtils.getProperty("dubbo.protocol.contextpath","default")));
        stringBuffer.append(String.format(CONSOLE_FORMAT,"spring xml path:"+ConfigUtils.getProperty("dubbom.spring.xml","classpath*:META-INF/spring/*.xml")));


        pringLIne(stringBuffer);
    }

    private static void pringLIne(StringBuffer stringBuffer){
        stringBuffer.append("+--------------------------------------------------------------------------------------+\n");
    }

    private static void printApp(File appDir,StringBuffer stringBuffer){
        stringBuffer.append(String.format(CONSOLE_FORMAT,appDir.getName()));
        File[] files = appDir.listFiles();
        for(File file:files){
            stringBuffer.append(String.format(CONSOLE_FORMAT," "+file.getName()));
        }
    }

    public static void start(StringBuffer info){
        String springXMLPath = ConfigUtils.getProperty("dubbom.spring.xml","classpath*:META-INF/spring/*.xml");
        String workDir = System.getProperty("work.dir");
        File apps = new File(workDir);
        File[] files = apps.listFiles(new FileFilter() {
            @Override
            public boolean accept(File pathname) {
                return !pathname.getName().endsWith("tar.gz");
            }
        });
        for(File file:files){
            clean(file);
        }
        files = apps.listFiles();
        if(files.length>0){
            info.append(String.format("|                                        Application Info                              |\n"));
            pringLIne(info);
            List<URL> jarsUrl = new ArrayList<URL>();
            for(File file:files){
                try {
                    File app = unCompress(file);
                    printApp(app,info);
                    File[] jars = app.listFiles(new FileFilter() {
                        @Override
                        public boolean accept(File pathname) {
                            return pathname.getName().endsWith(".jar");
                        }
                    });
                    for(File jar:jars){
                        jarsUrl.add(jar.toURI().toURL());
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    System.exit(0);
                }
            }
            URLClassLoader urlClassLoader = new URLClassLoader(jarsUrl.toArray(new URL[0]),Launcher.class.getClassLoader());
            Thread.currentThread().setContextClassLoader(urlClassLoader);
            String[] paths = StringUtils.split(springXMLPath,",");
            applicationContext = new ClassPathXmlApplicationContext(paths);
            applicationContext.setClassLoader(urlClassLoader);
            applicationContext.start();
            pringLIne(info);
            System.out.println();
            System.out.println(info.toString());
            System.out.print("DubboM launcher started!");
            synchronized (Launcher.class) {
                while (running) {
                    try {
                        Launcher.class.wait();
                    } catch (Throwable e) {
                    }
                }
            }
        }else{
            info.append(String.format("|                                         No Application                               |\n"));
            pringLIne(info);
            System.out.println();
            System.out.println(info.toString());
        }
    }

    private static File unCompress(File file) throws IOException, CompressorException {
        CompressorInputStream gzipInputStream = new CompressorStreamFactory().createCompressorInputStream(CompressorStreamFactory.GZIP,new FileInputStream(file));
        TarArchiveInputStream tarArchiveInputStream = new TarArchiveInputStream(gzipInputStream);
        TarArchiveEntry tarArchiveEntry = tarArchiveInputStream.getNextTarEntry();
        String name = file.getName();
        name=StringUtils.replace(name,COMPRESS_FILE_EXT,"");
        File targetDir = new File(file.getParent(),name);
        if(!targetDir.exists()){
            targetDir.mkdirs();
        }
        while(tarArchiveEntry!=null){
            File outFile = new File(targetDir,tarArchiveEntry.getName());
            FileOutputStream fileOutputStream = new FileOutputStream(outFile);
            IOUtils.copy(tarArchiveInputStream,fileOutputStream);
            fileOutputStream.flush();
            IOUtils.closeQuietly(fileOutputStream);
            tarArchiveEntry=tarArchiveInputStream.getNextTarEntry();
        }
        IOUtils.closeQuietly(tarArchiveInputStream);
        IOUtils.closeQuietly(gzipInputStream);
        return targetDir;

    }


    public static void stop(){

    }
}
